package com.kasuroid.core;

import android.view.KeyEvent;
import android.view.MotionEvent;

/**
 * Game state class definition.
 * 
 * @author Tomasz Rusak
 *
 */
public class GameState implements InputListener
{
    /** Keeps the current internal state of the game state. */
    private int mState = StateCode.TERMINATED;

    public GameState() {}

    public final int init()
    {
        Debug.inf(getClass().getName(), "init()");

        if (mState != StateCode.TERMINATED)
        {
            Debug.err(getClass().getName(), "Wrong state: " + StateCode.toString(mState));
            return RetCode.FAILURE;
        }

        int ret = onInit();
        if (ret != RetCode.SUCCESS)
        {
            Debug.err(getClass().getName(), "Problem with initialization!");
            return ret;
        }

        mState = StateCode.INITIALIZED;
        mState = StateCode.RUNNING;

        return RetCode.SUCCESS;
    }

    public final int term()
    {
        if (mState == StateCode.TERMINATED)
        {
            Debug.warn(getClass().getName(), "Game state already terminated!");
            return RetCode.SUCCESS;
        }

        int ret = onTerm();
        if (ret != RetCode.SUCCESS)
        {
            Debug.err(getClass().getName(), "Problem with termination!");
            return ret;
        }

        mState = StateCode.TERMINATED;
        return RetCode.SUCCESS;
    }

    public final int pause()
    {
        if (mState == StateCode.PAUSED)
        {
            Debug.warn(getClass().getName(), "Already paused");
            return RetCode.SUCCESS;
        }

        if (mState != StateCode.RUNNING)
        {
            Debug.err(getClass().getName(), "Can't pause not running state: " + StateCode.toString(mState));
            return RetCode.FAILURE;
        }

        int ret = onPause();
        if (ret != RetCode.SUCCESS)
        {
            Debug.err(getClass().getName(), "Problem with pausing the state!");
            return ret;
        }

        mState = StateCode.PAUSED;
        return RetCode.SUCCESS;
    }

    public final int resume()
    {
        if (mState == StateCode.RUNNING)
        {
            Debug.warn(getClass().getName(), "Already running");
            return RetCode.SUCCESS;
        }

        if (mState != StateCode.PAUSED)
        {
            Debug.err(getClass().getName(), "Can't resume not paused state: " + StateCode.toString(mState));
            return RetCode.FAILURE;
        }

        int ret = onResume();
        if (ret != RetCode.SUCCESS)
        {
            Debug.err(getClass().getName(), "Problem with resuming the state!");
            return ret;
        }

        mState = StateCode.RUNNING;
        return RetCode.SUCCESS;
    }

    public final int update()
    {
        if (mState == StateCode.PAUSED)
        {
            // Do not update when state is paused.
            return RetCode.SUCCESS;
        }

        if (mState != StateCode.RUNNING)
        {
            Debug.err(getClass().getName(), "Wrong state: " + StateCode.toString(mState));
            return RetCode.FAILURE;
        }

        return onUpdate();
    }

    public final int render()
    {
        if ((mState != StateCode.RUNNING) &&
            (mState != StateCode.PAUSED))
        {
            Debug.err(getClass().getName(), "Wrong state: " + StateCode.toString(mState));
            return RetCode.FAILURE;
        }

        return onRender();
    }

    public int onInit()
    {
        return RetCode.SUCCESS;
    }

    public int onTerm()
    {
        return RetCode.SUCCESS;
    }

    public int onUpdate()
    {
        return RetCode.SUCCESS;
    }

    public int onRender()
    {
        return RetCode.SUCCESS;
    }

    public int onPause()
    {
        return RetCode.SUCCESS;
    }

    public int onResume()
    {
        return RetCode.SUCCESS;
    }

    /**
     * Helper method for changing the current state.
     * 
     * @param gameState
     * @return
     */
    public int changeState(GameState gameState)
    {
        int ret = Core.getInstance().changeState(gameState);
        if (ret != RetCode.SUCCESS)
        {
            Debug.err(getClass().getName(), "Problem with changing the state!");
            return ret;
        }

        return ret;
    }

    /**
     * Helper method for pushing new game state to the states stack.
     * 
     * @param gameState
     * @return
     */
    public int pushState(GameState gameState)
    {
        int ret = Core.getInstance().pushState(gameState);
        if (ret != RetCode.SUCCESS)
        {
            Debug.err(getClass().getName(), "Problem with pushing the state to the stack!");
            return ret;
        }

        return ret;
    }

    /**
     * Helper method for popping the current state from the states stack.
     * 
     * @param gameState
     * @return
     */
    public int popState()
    {
        int ret = Core.getInstance().popState();
        if (ret != RetCode.SUCCESS)
        {
            Debug.err(getClass().getName(), "Problem with popping the state from the stack!");
            return ret;
        }

        return ret;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent msg)
    {
        return false;
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent msg)
    {
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        return false;
    }

    /**
     * Called when screen was created.
     * @return
     */
    public int onScreenCreated()
    {
        return RetCode.SUCCESS;
    }

    /**
     * Called when screen was destroyed.
     * @return
     */
    public int onScreenDestroyed()
    {
        return RetCode.SUCCESS;
    }

    /**
     * Called when screen size has changed.
     * @return
     */
    public int onScreenChanged(int width, int height)
    {
        return RetCode.SUCCESS;
    }
}
